// vmimage.cpp
//
// Copyright (C) 2008  Maksim Sipos <msipos@mailc.net>
//
// This file is a part of the Ripe language project.
//
// Ripe is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "util/standard.hpp"
#include <cstring>
#include "util/serialize.hpp"
#include "adts/map.hpp"
#include "vm/vmimage.hpp"

namespace Ripe {

using std::memcpy;
using std::strcmp;

ErrorInvalidVMImage::ErrorInvalidVMImage(const char* s)
{
  what = s;
}

VMSection::~VMSection()
{
}

VMSectionSymbol::VMSectionSymbol()
{
  flags = R_SECTION_SYMBOL;
}

void VMSectionSymbol::save(OSerializer* s)
{
  s->serialize(symbols.size);
  for (uint32_t i = 0; i < symbols.size; i++){
    s->serialize(symbols[i]);
  }
}

void VMSectionSymbol::load(ISerializer* s)
{
  uint32_t n_symbols = s->unserialize_uint32();
  for (uint32_t i = 0; i < n_symbols; i++){
  }
}

VMSectionCode::VMSectionCode()
{
  flags = R_SECTION_CODE;
}

void VMSectionCode::save(OSerializer* s)
{
  s->serialize(units.size);
  for (uint32_t i = 0; i < units.size; i++){
    s->serialize((uint32_t) units[i]);
  }
}

void VMSectionCode::load(ISerializer* s)
{
  uint32_t n_units = s->unserialize_uint32();
  for (uint32_t i = 0; i < n_units; i++){
    units.append((Unit) s->unserialize_uint32());
  }
}

VMSectionDirect::VMSectionDirect()
{
  flags = R_SECTION_DIRECT;
}
      
void VMSectionDirect::save(OSerializer* s)
{
  s->serialize(directs.size);
  for (uint32_t i = 0; i < directs.size; i++){
    s->serialize(directs[i].type);
    switch(directs[i].type){
      case DV_STRING:
        s->serialize(directs[i].string);
        break;
      case DV_INTEGER:
        s->serialize(directs[i].integer);
        break;
    }
  }
}

void VMSectionDirect::load(ISerializer* s)
{

}


VMImage::VMImage(ISerializer* s)
{
  try {
    // Check magic string
    char* magic = s->unserialize_string();
    if (strcmp(magic, "RipeVM") != 0)
      throw ErrorInvalidVMImage("Invalid magic string.");

    // Check the version
    uint32_t ver = s->unserialize_uint32();
    if (ver > R_VER_MAJOR)
      throw ErrorInvalidVMImage("This program needs newer version of Ripe.");
    ver = s->unserialize_uint32(); // TODO: Think of something to do with
                                   // minor version.

    // Unserialize the sections.
    uint32_t n_sections = s->unserialize_uint32();
    for (uint32_t i = 0; i < n_sections; i++){
      uint32_t sct_flags = s->unserialize_uint32();
      char* sct_name = s->unserialize_string();
    }
  } catch (ErrorUnserializeType e){
    throw ErrorInvalidVMImage("Invalid serialization.");
  }
}

VMImage::VMImage()
{
}

void VMImage::save(OSerializer* s)
{
  s->serialize("RipeVM");
  uint16_t ver_major = R_VER_MAJOR;
  uint16_t ver_minor = R_VER_MINOR;
  s->serialize(ver_major);
  s->serialize(ver_minor);
  s->serialize(sections.size);

  // Serialize the sections.
  for (uint32_t i = 0; i < sections.size; i++){
    s->serialize(sections[i]->flags);
    s->serialize(sections[i]->name);
    sections[i]->save(s);
  }
}

}
